package com.cold.legendary.mock.proxy;

import com.cold.legendary.mock.context.prepare.PreMockContext;
import com.cold.legendary.mock.context.prepare.PrepareContextManager;
import com.cold.legendary.mock.context.prepare.element.PreMockBeanElement;
import com.cold.legendary.mock.context.prepare.element.PreMockElement;
import com.cold.legendary.mock.context.runnable.RunContextManager;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @author cold
 * @since  2022/1/19
 */
public class LMockMethodInterceptor implements MethodInterceptor {

    private Object mockInjectBean;
    private String mockBeanName;
    private Object mockBean;

    public LMockMethodInterceptor(String mockBeanName, Object mockInjectBean, Object mockBean) {
        super();
        this.mockInjectBean = mockInjectBean;
        this.mockBeanName = mockBeanName;
        this.mockBean = mockBean;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        PreMockContext preMockContext = PrepareContextManager.getPreMockContext();
        //如果preMockContext被清理掉了,那么不进行mock
        if(null == preMockContext) {
            return method.invoke(mockBean, args);
        }

        //无论是否mock过,计数器直接增加,这样做的好处是,可以指定第一次mock,第二次不mock,第三次mock这种场景
        RunContextManager.addRunMockCount(mockInjectBean.getClass().getName(), mockBeanName, method.getName());
        //获取当前计数值
        Integer runCount = RunContextManager.getRunMockCount(mockInjectBean.getClass().getName(), mockBeanName, method.getName());
        //获取prepare的mock result
        PreMockBeanElement preMockBeanElement = getPrepareMockResult(preMockContext,
                mockInjectBean.getClass().getTypeName(), mockBeanName, method.getName(), runCount);
        //是否需要mock
        if (null != preMockBeanElement) {
            //mock方法不再进行反射调用真正的方法,直接实例化出mock结果.反射赋值;
            return preMockBeanElement.getPreMockResult();
        }
        //不需要mock,那么正常调用
        //return methodProxy.invokeSuper(obj, args);
        return method.invoke(mockBean, args);
    }

    /**
     * 获取预加载mock结果
     *
     * @param preMockContext
     * @param runInjectBeanName
     * @param runBeanName
     * @param runMethodName
     * @param runCount
     * @return
     */
    private PreMockBeanElement getPrepareMockResult(PreMockContext preMockContext, String runInjectBeanName,
                                                    String runBeanName, String runMethodName, Integer runCount) {
        List<PreMockElement> preMockElements = preMockContext.getPreMockElements();
        if(null == preMockElements) {
            return null;
        }
        PreMockBeanElement preMockBeanElement = preMockElements.stream().filter(e -> e.getPreMockInjectBeanName().equals(runInjectBeanName))
                .flatMap(e -> e.getPreMockBeanElements().stream())
                .filter(e -> e.getPreMockBeanName().equals(runBeanName))
                .filter(e -> e.getPreMockBeanMethodName().equals(runMethodName))
                .filter(e -> e.getPreRunTimes().equals(runCount))
                .findFirst().orElse(null);
        return preMockBeanElement;
    }
}
